#ifndef _BUOLA_GRAPH_CPROPERTY_H_
#define _BUOLA_GRAPH_CPROPERTY_H_

#include <buola/buola.h>
#include <boost/property_map/property_map.hpp>
#include <buola/iterator/subscript.h>

namespace buola { namespace graph {

template<typename tGraph,typename tValue>
class CVertexProperty
{
    typedef typename tGraph::vertex_descriptor TIndex;
    typedef std::vector<tValue> TData;
    typedef boost::typed_identity_property_map<TIndex> TIndexMap;
    
public:
    explicit CVertexProperty(const tGraph &pGraph)
        :   mData(pGraph.MaxVertexDescriptor()+1)
        ,   mGraph(pGraph)
    {}
    
    explicit CVertexProperty(const tGraph &pGraph,const tValue &pValue)
        :   mData(pGraph.MaxVertexDescriptor()+1,pValue)
        ,   mGraph(pGraph)
    {}
    
    CVertexProperty(const CVertexProperty&)=default;
    CVertexProperty(CVertexProperty&&)=default;
    CVertexProperty &operator=(const CVertexProperty&)=default;
    CVertexProperty &operator=(CVertexProperty&&)=default;
    
    tValue &operator[](TIndex pIndex)               {   return mData[pIndex];   }
    const tValue &operator[](TIndex pIndex) const   {   return mData[pIndex];   }
    
    template<typename tRange>
    auto operator[](const tRange &pRange) -> decltype(subscript_range(pRange,*this))
    {
        return subscript_range(pRange,*this);
    }
    
    boost::iterator_property_map<typename TData::iterator,TIndexMap> Map()
    {
        return make_iterator_property_map(mData.begin(),boost::typed_identity_property_map<TIndex>());
    }
    
private:
    TData mData;
    const tGraph &mGraph;
};

template<typename tType,typename tGraph>
CVertexProperty<tGraph,tType> new_vertex_property(const tGraph &pGraph)
{
    return CVertexProperty<tGraph,tType>(pGraph);
}

template<typename tType,typename tGraph>
CVertexProperty<tGraph,tType> new_vertex_property(const tGraph &pGraph,const tType &pValue)
{
    return CVertexProperty<tGraph,tType>(pGraph,pValue);
}

namespace detail {
    
    template<typename tContainer>
    struct AClassifyPropertyMap
    {
        //for boost
        typedef typename tContainer::value_type::value_type key_type;
        typedef int value_type;
        typedef void reference;
        typedef boost::writable_property_map_tag category;
        
        explicit AClassifyPropertyMap(tContainer &pContainer)
            :   mContainer(pContainer)
        {}
            
        tContainer &mContainer;
    };

    template<typename tContainer,typename tKey>
    void put(const AClassifyPropertyMap<tContainer> &pResult,const tKey &pKey,int pValue)
    {
        if(pResult.mContainer.size()<=pValue)
            pResult.mContainer.resize(pValue+1);
        pResult.mContainer[pValue].push_back(pKey);
    }

/*namespace detail*/ }
    
template<typename tContainer>
detail::AClassifyPropertyMap<tContainer> classify_map(tContainer &pContainer)
{
    return detail::AClassifyPropertyMap<tContainer>(pContainer);
}

template<typename tGraph>
std::vector<std::vector<typename tGraph::vertex_descriptor>> new_vertex_classifier(const tGraph &pGraph)
{
    return {};
}
    
/*namespace graph*/ } /*namespace buola*/ }

#endif
